Wavefront OBJ File


Wavefront .obj file

An *.obj file is a file format to store 3D geometry. It is a text file that stores the position of each vertex and the UV position of each texture. The vertices are stored in counter-clockwise order by default.
Un archivo *.obj es un formato de archivo para almacenar geometría de 3D. Este es un archivo de texto que almacena la posición de cada vértice y la position UV de cada textura. Los vértices están almacenados en dirección contraria a las manecillas del reloj por defecto.

Geometric vertices

The example below shows a simple OBJ file. The first example has a list with four vertices. Each vertex begins with the letter v and has three parameters (x, y, z). Each vertex in the second example has four parameters: x, y, z and the weight. If the weight of the vertex is not specified, it is assumed to be 1.
El ejemplo de abajo muestra un archivo OBJ simple. El primer ejemplo tiene una lista con cuatro vértices. Cada vértice comienza con la letra v y tiene tres parámetros (x, y, z). Cada vértice en el segundo ejemplo tiene cuatro parámetros: x, y, z y el peso. Si el peso del vértice no se específica, se asume que uno.

vertex

Texture coordinates

The example below shows a simple OBJ file. The first example has a list with three texture coordinates. Each texture coordinate begins with vt and has two parameters (u, v). Each texture coordinate in the second example has three parameters: u, v and the weight. If the weight of the texture coordinate is not specified, it is assumed to be 1.
El ejemplo de abajo muestra un archivo OBJ simple. El primer ejemplo tiene una lista con tres coordenadas de textura. Cada coordenada de textura comienza con vt y tiene dos parámetros (u, v). Cada coordenada de la textura en el segundo ejemplo tiene tres parámetros: u, v y el peso. Si el peso de la coordenada de la textura no se específica, se asume que es uno.

texture

OBJ format

The figure below shows the structure of an OBJ document.
  1. The document has a set of nodes
  2. Each node has a name, a set of vertexes, a set of normal vectors, a set of vector textures and a set of face groups
  3. Each face group has a usemtl and a set of polygons
  4. Each polygon has three sets of indexes

  1. El documento tiene un conjunto de nodos
  2. Cada nodo tiene un nombre, un conjunto de vértices, un conjunto de vectores normales, un conjunto de vectores de texturas y un conjunto de face groups
  3. Cada grupo de face tiene un usemtl y un conjunto de poligonos
  4. Cada polígono tiene tres conjuntos de índices

format

OBJ Example

The example below shows a simple OBJ file. The file has five parts: vertices, texture, vertex normal, parameter space and face. A polygonal face begins with f and may have a several groups of numbers. Each triple has three numbers: a vertex index, a texture index and a normal index. The first face has three triples: 1/2/3, 2/2/1 and 3/2/3. In the last triple, the first number, 3, is the vertex index; the second number, 2, is the texture index and the last number, 3, is the normal index. When the texture index is not provided, it is possible to denote a triple as 3//2. When both, the texture index and the normal index are not provided, it is possible to denote a triple by only the vertex index.
El ejemplo de abajo muestra un archivo OBJ sencillo. El archivo tiene cinco partes: vertices, texture, vertex normal, parameter space and face. Un cara poligonal comienza con f y puede tener varios triples. Cada triple tiene tres números: un índice para el vértice, un índice para la textura y un índice para la normal. La primera cara tiene tres triples: 1/2/3, 2/2/1 y 3/2/3. En el último triple, el primer número, 3, es el índice del vértice; el segundo número, 2, es el índice la textura y el último número, 3, es el índice de la normal. Cuando no se proporciona el índice la textura, es posible denotar un triple cómo 3//2. Cuando los dos, el índice de la textura y el índice la normal no se proporcionan, es posible denotar el triple solamente por el índice del vértice.

example

Other elements

The OBJ file also has the following elements:
  1. Line elements, they start with l
  2. Point elements, they start with p
  3. Object name, denoted by o
  4. Polygon group, denoted by g
  5. Smooth shading, denoted by s
  6. Curve, denoted by curv
  7. Surface, denoted by surf

El archivo OBJ también los siguientes elementos:
  1. Elementos de línea, estos comienzan con l
  2. Elementos de puntos, estos comienzan con p
  3. Nombres de objetos, indicados por una letra o
  4. Grupos de polígonos, indicados por una letra g
  5. Sombreado suave, denotado por una letra s
  6. Curva, denotado por curv
  7. Superficie, denotado por surf

Tip
You may download the OBJ specification from http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
Usted puede descargar la especificación OBJ desde http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf

Material Template Library (*.MTL)

It is an ASCII file format that works together with one or more *.OBJ files. An *.MTL file stores material properties and is typically called a material library. This file includes properties of a surface, such as light reflection.
  • Ka ambient color: the amount of light scattered in the entire scene. A value from 0 to 1 for red, a value from 0 to 1 for green and a value from 0 to 1 for blue.
  • Kd diffuse color: it commonly contributes most of the color. A value from 0 to 1 for red, a value from 0 to 1 for green and a value from 0 to 1 for blue.
  • Ks specular color: the observed color when the surface is shiny like a mirror. A value from 0 to 1 for red, a value from 0 to 1 for green and a value from 0 to 1 for blue.

Este es un formato ASCII para archivos que trabaja en conjunto con uno o varios archivos as *.OBJ. Un archivo *.MTL almacena propiedades de materiales y es típicamente llamado una librería de materiales. Este archivo incluye propiedades de una superficie, tales como la reflexión de la luz.
  • Ka color ambiental: la cantidad de luz distribuida en la escena completa. Un valor de 0 a 1 para el rojo, un valor de 0 a 1 para el verde y un valor de 0 a 1 para el azul.
  • Kd color difuso: este es el que contribuye en su mayoría al color del objeto. Un valor de 0 a 1 para el rojo, un valor de 0 a 1 para el verde y un valor de 0 a 1 para el azul.
  • Ks color de reflejo: el color que se observa cuando la superficie es brillante como un espejo. Un valor de 0 a 1 para el rojo, un valor de 0 a 1 para el verde y un valor de 0 a 1 para el azul.

Problem 1
Cree a dialog application called ObjReader to read an OBJ file and display the vertexes of the faces in the file (note that this is NOT a DirectX application). After creating the project insert textbox called tbxOutput to show the vertexes values. Then, use notepad to create the file shown below, you may download a simple OBJ file from the Internet. If the file is too big, it will be impossible to display all the vertexes in a textbox.
Cree una aplicación de diálogo llamada ObjReader para leer un archivo OBJ y mostrar los vértices de las caras en el archivo (note que esta NO es una aplicación de DirectX). Después de crear el proyecto inserte una caja de texto llamada tbxOutput para mostrar los valores de los vértices. Entonces, use el block de notas para crear el archivo mostrado debajo, usted puede descargar un archivo OBJ sencillo desde la Internet. Si el archivo es demasiado grande, será imposible mostrar todos los vértices en una caja de texto.

cube.obj
# This file uses centimeters as units for non-parametric coordinates.

mtllib cube.mtl
g default
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.998008 0.998008
vt 0.001992 0.998008
vt 0.998008 0.001992
vt 0.001992 0.001992
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s 1
g pCube1
usemtl file1SG
f 1/1/1 2/2/2 3/3/3
f 3/3/3 2/2/2 4/4/4
s 2
f 3/13/5 4/14/6 5/15/7
f 5/15/7 4/14/6 6/16/8
s 3
f 5/21/9 6/22/10 7/23/11
f 7/23/11 6/22/10 8/24/12
s 4
f 7/17/13 8/18/14 1/19/15
f 1/19/15 8/18/14 2/20/16
s 5
f 2/5/17 8/6/18 4/7/19
f 4/7/19 8/6/18 6/8/20
s 6
f 7/9/21 1/10/22 5/11/23
f 5/11/23 1/10/22 3/12/24


ObjReader.h
#pragma once //______________________________________ ObjReader.h
#include "Resource.h"
class ObjReader: public Win::Dialog
{
public:
     ObjReader()
     {
     }
     ~ObjReader()
     {
     }
     void DisplayObject(Sys::ObjDocument& document, Sys::ObjNode& node);
     void DisplayFaceGroup(Sys::ObjFaceGroup& faceGroup, vector<Sys::Point3DF>& v);
protected:
     . . .
};


ObjReader.cpp
. . .
void ObjReader::Window_Open(Win::Event& e)
{
     Sys::ObjDocument document;
     const wchar_t* error = document.Load(L"cube.obj");
     if (error != NULL)
     {
          this->MessageBox(error, L"ObjReader", MB_OK | MB_ICONERROR);
          return;
     }
     const size_t nodeCount = document.o.size();
     for (size_t i = 0; i < nodeCount; i++) DisplayObject(document, document.o[i]);
}

void ObjReader::DisplayObject(Sys::ObjDocument& document, Sys::ObjNode& node)
{
     const size_t faceGroupCount = node.faceGroup.size();
     for (size_t i = 0; i < faceGroupCount; i++) DisplayFaceGroup(node.faceGroup[i], document.v);
}

void ObjReader::DisplayFaceGroup(Sys::ObjFaceGroup& faceGroup, vector<Sys::Point3DF>& v)
{
     //if (faceGroup.usemtl.empty() == false) usemtlList.insert(faceGroup.usemtl);
     const size_t rowCount = faceGroup.polygon.size();
     size_t colCount;
     wchar_t text[128];
     size_t index, i, j;
     for (i = 0; i < rowCount; i++)
     {
          colCount = faceGroup.polygon[i].size();
          tbxOutput.Text += L"________________________ Face\r\n";
          for (j = 0; j < colCount; j++)
          {
               index = faceGroup.polygon[i][j].vertexIndex - 1; // C++ indexes begins at zero
               _snwprintf_s(text, 128, _TRUNCATE, L"%.6f, %.6f, %.6f\r\n", v[index].x, v[index].y, v[index].z);
               tbxOutput.Text += text;
          }
     }
}

ObjReaderRun

Problem 2
Create a DirectX application called MyView to display some of the faces in an OBJ file. After creating the project, add a DirectX scene called MainScene and a DirectX object called Body.
Cree una aplicación DirectX llamada MyView para mostrar algunas de las caras de un archivo OBJ. Después de crear el proyecto, agregue una escena de DirectX llamada MainScene y un objeto de DirectX llamado Body.

MyViewRun1

MyViewRun2

Step A
Use notepad to open the OBJ file and see what is inside the file. Use a very simple obj file for this exercise such as a cube. Be sure that your file has normal vectors (vn), if your file does not have normal vectors, lighting will not work.
Use el block de notas para abrir el archivo OBJ y vea el contenido del archivo. Use un archivo obj muy simple para este ejercicio tal como un cubo. Asegúrese de que su archivo tiene vectores normales (vn), si su archivo no tiene vectores normales, la iluminación no funcionará.

Step B
Edit the Body.h file as shown.
Edite el archivo Body.h cómo se muestra.

Body.h
//____________________________________________________________ Body.h
#pragma once

class Body : public DX11::Object3D
{
public:
     float x = 0.0f;
     float y = 0.0f;
     float z = 0.0f;
     float angleY = 0.0f;
     DirectX::XMMATRIX scale = DirectX::XMMatrixScaling(1.2f, 1.2f, 1.2f);
     //
     bool OnCreateScene(DX11::Engine& engine);
     . . .
};


Step C
Edit the Body.cpp file as shown. Be sure to use a shader for color and diffuse lighting, DX11::ColorDiffuseLightShader shaderColorDiffuse.
Edite el archivo Body.cpp cómo se muestra. Asegúrese de usar un shader para color y luz difusa, DX11::ColorDiffuseLightShader shaderColorDiffuse.

Body.cpp
. . .
void Body::OnUpdate(DX11::Engine& engine, float sec, float deltaSec)
{
     angleY += (0.5f*deltaSec);
     world = DirectX::XMMatrixRotationY(angleY);
     DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(x, y, z);
     world = DirectX::XMMatrixMultiply(world, translation);
     world = DirectX::XMMatrixMultiply(scale, world);
     if (angleY > DirectX::XM_2PI) angleY -= DirectX::XM_2PI;
}
. . .


Step D
Edit the files: MainScene.h, MainScene.cpp, MyView.h and MyView.cpp.
Edite los archivos: MainScene.h, MainScene.cpp, MyView.h y MyView.cpp.

MainScene.h
//____________________________________________________________ MainScene.h
#pragma once
#include "Body.h"

class MainScene : public DX11::Scene
{
public:
     Body body;
     void OnCreateScene(DX11::Engine& engine);
     . . .
};


MainScene.cpp
. . .
void MainScene::OnCreateScene(DX11::Engine& engine)
{
     //______________________________ 1. Set back color RGBA
     this->SetBackColor(0.0f, 0.0f, 0.4f, 1.0f);
     //______________________________ 2. Add children
     this->AddChild(body);
     . . .
}
. . .


MyView.h
#pragma once //______________________________________ MyView.h
#include "Resource.h"
#include "MainScene.h"

class MyView : public DX11::Window
{
public:
     MainScene mainScene;
     DX11::ColorNormVertexBuffer vb;
};


MyView.cpp
. . .
int APIENTRY wWinMain(. . .)
{
     MyView app;
     //_________________________________________________________ 1. Load obj file
     Sys::ObjDocument document;
     const wchar_t* error = document.Load(L"cube.obj");
     if (error != nullptr)
     {
          ::MessageBox(NULL, error, L"cube.obj", MB_OK | MB_ICONERROR);
          return 0;
     }
     //_________________________________________________________ 2. Create vertex buffers
     const int nodeIndex = 0;
     const int faceGroupIndex = 0;
     // 1. Set count
     const unsigned int indexCount = (unsigned int)document.GetTotalIndexCount(false);
     const unsigned int vertexCount = (unsigned int)document.GetTotalVertexCount();
     if (app.vb.CreateData(indexCount, vertexCount, D3D11_USAGE_DEFAULT, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) == false)
     {
          ::MessageBox(NULL, L"Unable to create vertex buffer", L"BasicX", MB_OK | MB_ICONERROR);
          return 0;
     }
     // 2. Process the vertexes (perform transformations, if necessary)
     DX11::ColorNormVertex *vertex = app.vb.vertex;
     unsigned long *index = app.vb.index;
     size_t i = 0;
     Sys::IndexGenerator indexGenerator;
     Sys::ColorF color(1.0f, 0.0f, 0.0f, 1.0f); //RGBA
     Sys::Point3DF* point = nullptr;
     std::vector<std::vector<Sys::ObjFacePoint> >::iterator p = document.o[nodeIndex].faceGroup[faceGroupIndex].polygon.begin();
     std::vector<std::vector<Sys::ObjFacePoint> >::iterator pe = document.o[nodeIndex].faceGroup[faceGroupIndex].polygon.end();
     std::vector<Sys::ObjFacePoint>::iterator q;
     std::vector<Sys::ObjFacePoint>::iterator qe;

     for (; p != pe; p++) //____________ polygon[][]
     {
          qe = p->end();
          //___________________________ VERTEX
          for (q = p->begin(); q != qe; q++)
          {
               point = &document.v[q->vertexIndex-1];
               vertex[i].position.x = point->x;
               vertex[i].position.y = point->y;
               vertex[i].position.z = point->z;
               vertex[i].color = DirectX::XMFLOAT4(color.red, color.green, color.blue, 1.0f);
               point = &document.vn[q->normalIndex-1];
               vertex[i].normal.x = point->x;
               vertex[i].normal.y = point->y;
               vertex[i].normal.z = point->z;
               i++;
          }
          //_________________________ INDEX
          indexGenerator.TriangleList(p->size(), index);
     }
     //_________________________________________________________ 3. Add vertex buffers to the engine
     app.engine.AddChild(app.vb);
     //_________________________________________________________ 4. Set vertex buffers to the 3D objects
     app.mainScene.body.vertexBuffer = &app.vb;
     //_________________________________________________________ 5. Scene setup
     app.engine.scene[L"mainScene"] = &app.mainScene;
     app.engine.SetCurrentScene(L"mainScene");
     //_________________________________________________________ 6. Run the app
     return app.Run(. . .);
}

Vertex Buffer    Normal vector    Lighting    color    texture  
DX10::ColorVertexBuffernonorequiredno
DX10::ColorNormVertexBufferrequiredyesrequiredno
DX10::TextureVertexBuffernononorequired
DX10::TextureNormVertexBufferrequiredyesnorequired

Problem 3
Create a DirectX program called DisplayX to draw the content of an OBJ file. The objects in the file must turn around Y axis. You need the following files for this problem: IronMan.obj and IronMan.mtl. You can download these files from a 3D models website. After creating the project, add a DirectX scene called MainScene and a DirectX object called Body.
Cree un programa de DirectX llamado DisplayX para dibujar el contenido de un archivo OBJ. Los objetos en el archivo deben girar alrededor del eje Y. Usted necesita los siguientes archivos para este problema: IronMan.obj and IronMan.mtl. Usted puede descargar estos archivos desde un sitio web de modelos 3D. Después de crear el proyecto, agregue una escena de DirectX llamada MainScene y un objecto de DirectX llamado Body.

DisplayXFolder

DisplayXRun1

DisplayXRun2

Body.h
//____________________________________________________________ Body.h
#pragma once

class Body : public DX11::Object3D
{
public:
     float x = 0.0f;
     float y = 0.0f;
     float z = 0.0f;
     float angleY = 0.0f;
     DirectX::XMMATRIX scale = DirectX::XMMatrixScaling(1.2f, 1.2f, 1.2f);
     //
     bool OnCreateScene(DX11::Engine& engine);
     . . .
};


Body.cpp
. . .
void Body::OnUpdate(DX11::Engine& engine, float sec, float deltaSec)
{
     //________________________________________________________ 1. Rotate, translate and scale
     angleY += (0.5f*deltaSec);
     world = DirectX::XMMatrixRotationY(angleY);
     DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(x, y, z);
     world = DirectX::XMMatrixMultiply(world, translation);
     world = DirectX::XMMatrixMultiply(scale, world);
     if (angleY > DirectX::XM_2PI) angleY -= DirectX::XM_2PI;
}

void Body::OnRender3D(DX11::Engine& engine)
{
     engine.shaderColorAmbient.Render(engine, world, vertexBuffer->GetIndexCount(), 0, 0);
}
. . .


MainScene.h
//____________________________________________________________ MainScene.h
#pragma once
#include "Body.h"
class MainScene : public DX11::Scene
{
public:
     Body body;
     void OnCreateScene(DX11::Engine& engine);
     . . .
};


MainScene.cpp
. . .
void MainScene::OnCreateScene(DX11::Engine& engine)
{
     //______________________________ 1. Set back color RGBA
     this->SetBackColor(0.0f, 0.0f, 0.0f, 1.0f);
     //______________________________ 2. Add children
     this->AddChild(body);
     //______________________________ 3. Camera & Light setup (light.ambientColor)
     . . .
}


DisplayX.h
#pragma once //______________________________________ DisplayX.h
#include "Resource.h"
#include "MainScene.h"

class DisplayX : public DX11::Window
{
public:
     MainScene mainScene;
     DX11::ColorNormVertexBuffer vb;
};


DisplayX.cpp
. . .
int APIENTRY wWinMain(. . .)
{
     DisplayX app;
     //_________________________________________________________ 1. Load obj file
     Sys::ObjDocument document;
     const wchar_t* error = document.Load(L"IronMan.obj");
     if (error != nullptr)
     {
          ::MessageBox(NULL, error, L"IronMan.obj", MB_OK | MB_ICONERROR);
          return 0;
     }
     //_________________________________________________________ 2. Load mtl file
     Sys::MaterialTemplateLibrary mtl;
     error = mtl.Load(L"IronMan.mtl");
     if (error != nullptr)
     {
          ::MessageBox(NULL, error, L"IronMan.mtl", MB_OK | MB_ICONERROR);
          return 0;
     }
     //_________________________________________________________ 3. Create vertex buffers
     if (app.vb.CreateData(document, mtl, false) == false)
     {
          ::MessageBox(NULL, L"Unable to create vertex buffer", L"DisplayX", MB_OK | MB_ICONERROR);
          return 0;
     }
     //_________________________________________________________ 4. Add vertex buffers to the engine
     app.engine.AddChild(app.vb);
     //_________________________________________________________ 5. Set vertex buffers to the 3D objects
     app.mainScene.body.vertexBuffer = &app.vb;
     //_________________________________________________________ 6. Scene setup
     app.engine.scene[L"mainScene"] = &app.mainScene;
     app.engine.SetCurrentScene(L"mainScene");
     //_________________________________________________________ 7. Run the app
     return app.Run(. . .);
}

© Copyright 2000-2021 Wintempla selo. All Rights Reserved. Jul 22 2021. Home